﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ttbit.core;
using ttbit.form.impl;
using System.Numerics;

namespace ttbit.form.impl
{
    class Renderer_Batcher : IBatcher
    {

        Graphics graphics;
        CommonRenderParam currentRenderParam;

        public IRenderTarget Target
        {
            get;
            private set;
        }
        public Renderer_Batcher(Graphics graphics, IRenderTarget target)
        {
            this.graphics = graphics;
            this.Target = target;
            currentRenderParam = new CommonRenderParam();
        }
        public void BeginDraw()
        {
            currentRenderParam.matWorld.Mat3Init();
            Vector2 lookat =new Vector2(-this.LookAt.X,-this.LookAt.Y);

            currentRenderParam.matView.Mat3GenTRS(lookat, 0, new Vector2(this.Scale));
            currentRenderParam.matProj.Mat3Proj(Target.width, Target.height, Target.FlipY ? true : false);
        }
        public void EndDraw()
        {
            batcher.EndFrame();
        }

        public string Name => "Batcher";

        public Vector2 LookAt { get; set; }
        public float Scale { get; set; } = 1.0f;

        public QuadBatchRenderer batcher = new QuadBatchRenderer();
        public void DrawLines(ITexture tex, Effect effect, DrawPoint[] lines, int linecount)
        {
            throw new NotImplementedException();
        }

        public void DrawPoints(ITexture tex, Effect effect, DrawPoint[] points, int pointcount)
        {
            throw new NotImplementedException();
        }
        ITexture texLast;
        Effect effLast;
        public void DrawRect(ITexture tex, Effect effect, RectangleF rect, Rectangle uv, Color32 color)
        {

            if (matDef == null)
                matDef = new Material(tex.format == TextureFormat.R8 ? ShaderPool.GetShader("gray") : ShaderPool.GetShader("base"));

            if (texLast != tex || effLast != effect)
            {
                batcher.EndFrame();
                texLast = tex;
                effLast = effect;
                matDef.ChangeShader(tex.format == TextureFormat.R8 ? ShaderPool.GetShader("gray") : ShaderPool.GetShader("base"));

            }
            matDef.UpdateContext(currentRenderParam);


            if (tex is FormTexture ftex)
            {
                matDef.texMain = ftex.nativeTex;

            }
            else if (tex is FormRenderTexture rtex)
            {
                matDef.texMain = rtex.nativeTex;
            }
            else
            {
                throw new Exception("error tex");
            }

            var r1 = batcher.ReqBuf(4, matDef);

            float x = rect.X;
            float y = rect.Y;
            float x2 = rect.X + rect.Width;
            float y2 = rect.Y + rect.Height;

            r1.buffer[r1.seek + 0].X = x;
            r1.buffer[r1.seek + 0].Y = y;
            r1.buffer[r1.seek + 0].R = color.R;
            r1.buffer[r1.seek + 0].G = color.G;
            r1.buffer[r1.seek + 0].B = color.B;
            r1.buffer[r1.seek + 0].A = color.A;
            r1.buffer[r1.seek + 0].U = (float)uv.X / tex.width;
            r1.buffer[r1.seek + 0].V = (float)uv.Y / tex.height;

            r1.buffer[r1.seek + 1].X = x2;
            r1.buffer[r1.seek + 1].Y = y;
            r1.buffer[r1.seek + 1].R = color.R;
            r1.buffer[r1.seek + 1].G = color.G;
            r1.buffer[r1.seek + 1].B = color.B;
            r1.buffer[r1.seek + 1].A = color.A;
            r1.buffer[r1.seek + 1].U = (float)(uv.X + uv.Width) / tex.width;
            r1.buffer[r1.seek + 1].V = (float)uv.Y / tex.height;

            r1.buffer[r1.seek + 2].X = x;
            r1.buffer[r1.seek + 2].Y = y2;
            r1.buffer[r1.seek + 2].R = color.R;
            r1.buffer[r1.seek + 2].G = color.G;
            r1.buffer[r1.seek + 2].B = color.B;
            r1.buffer[r1.seek + 2].A = color.A;
            r1.buffer[r1.seek + 2].U = (float)(uv.X) / tex.width;
            r1.buffer[r1.seek + 2].V = (float)(uv.Y + uv.Height) / tex.height;

            r1.buffer[r1.seek + 3].X = x2;
            r1.buffer[r1.seek + 3].Y = y2;
            r1.buffer[r1.seek + 3].R = color.R;
            r1.buffer[r1.seek + 3].G = color.G;
            r1.buffer[r1.seek + 3].B = color.B;
            r1.buffer[r1.seek + 3].A = color.A;
            r1.buffer[r1.seek + 3].U = (float)(uv.X + uv.Width) / tex.width;
            r1.buffer[r1.seek + 3].V = (float)(uv.Y + uv.Height) / tex.height;

        }

        Material matDef;
        //public void DrawRect(ITexture tex, RectangleF rect, Rectangle uv, Color32 color)
        //{
        //    DrawRect(tex, null, rect, uv, color);
        //}

        //public void DrawRect(ITexture tex, Vector2 pos, Rectangle uv, Color32 color)
        //{
        //    DrawRect(tex, null, new RectangleF(pos.X, pos.Y, uv.Width, uv.Height), uv, color);
        //}

        public void DrawRectFree(ITexture tex, Effect effect, DrawPoint point0, DrawPoint point1, DrawPoint point2, DrawPoint point3)
        {
            if (matDef == null)
                matDef = new Material(tex.format == TextureFormat.R8 ? ShaderPool.GetShader("gray") : ShaderPool.GetShader("color"));
            else
            {
                matDef.ChangeShader(tex.format == TextureFormat.R8 ? ShaderPool.GetShader("gray") : ShaderPool.GetShader("color"));
            }

            var r1 = batcher.ReqBuf(4, matDef);


            r1.buffer[r1.seek + 0].X = point0.pos.X;
            r1.buffer[r1.seek + 0].Y = point0.pos.Y;
            r1.buffer[r1.seek + 0].R = point0.color.R;
            r1.buffer[r1.seek + 0].G = point0.color.G;
            r1.buffer[r1.seek + 0].B = point0.color.B;
            r1.buffer[r1.seek + 0].A = point0.color.A;
            r1.buffer[r1.seek + 0].U = point0.uv.X / tex.width;
            r1.buffer[r1.seek + 0].V = point0.uv.Y / tex.height;

            r1.buffer[r1.seek + 1].X = point1.pos.X;
            r1.buffer[r1.seek + 1].Y = point1.pos.Y;
            r1.buffer[r1.seek + 1].R = point1.color.R;
            r1.buffer[r1.seek + 1].G = point1.color.G;
            r1.buffer[r1.seek + 1].B = point1.color.B;
            r1.buffer[r1.seek + 1].A = point1.color.A;
            r1.buffer[r1.seek + 1].U = point1.uv.X / tex.width;
            r1.buffer[r1.seek + 1].V = point1.uv.Y / tex.height;

            r1.buffer[r1.seek + 2].X = point2.pos.X;
            r1.buffer[r1.seek + 2].Y = point2.pos.Y;
            r1.buffer[r1.seek + 2].R = point2.color.R;
            r1.buffer[r1.seek + 2].G = point2.color.G;
            r1.buffer[r1.seek + 2].B = point2.color.B;
            r1.buffer[r1.seek + 2].A = point2.color.A;
            r1.buffer[r1.seek + 2].U = point2.uv.X / tex.width;
            r1.buffer[r1.seek + 2].V = point2.uv.Y / tex.height;

            r1.buffer[r1.seek + 3].X = point3.pos.X;
            r1.buffer[r1.seek + 3].Y = point3.pos.Y;
            r1.buffer[r1.seek + 3].R = point3.color.R;
            r1.buffer[r1.seek + 3].G = point3.color.G;
            r1.buffer[r1.seek + 3].B = point3.color.B;
            r1.buffer[r1.seek + 3].A = point3.color.A;
            r1.buffer[r1.seek + 3].U = point3.uv.X / tex.width;
            r1.buffer[r1.seek + 3].V = point3.uv.Y / tex.height;
        }

        public void DrawTris(ITexture tex, Effect effect, DrawPoint[] tris, int tricount)
        {
            throw new NotImplementedException();
        }

    }

}
